/*
 * task_fixd.c
 * 
 * Passive fixation task with an option of showing random-dots motion to the monkey
 *  (when dots aperture is greater than 0).
 *
 *
 *   Created by jcl on 1/24/08.
 *
 */

/* note to myself, need to be able to change
 *  1) fix time
 *  2) dots location/dir/dur/coh
 *  3) dots contrast (important)
 */

#include "../toys.h"
#include "../task.h"
#include "../task_utilities.h"


/* PRIVATE MACROS/CONSTANTS */
#define NUM_GR_MENUS 3
#define TTMV(ta,n) 	pl_list_get_v((ta)->task_menus->lists[0],(n))	/* timing */
#define TPMV(ta,n) 	pl_list_get_v((ta)->task_menus->lists[1],(n))	/* property */
#define TGMV(ta,n) 	pl_list_get_v((ta)->task_menus->lists[2],(n))	/* graphics */
#define TDMV(ta,n) 	pl_list_get_v((ta)->task_menus->lists[3],(n))	/* dots */

/* PRIVATE ROUTINES */
void		fixd_make_trials	(_PRtask);
_PRtrial	fixd_get_trial		(_PRtask, int);
void 		fixd_set_trial		(_PRtrial);

/* PRIVATE VARIABLES */

/* 
** TASK: FIXD ("Fixation plus passive motion-viewing")
*/
struct _TAtask_struct gl_fixd_task[] = {

	/*     name     */
	"fixd", 


	/*     menus     */
	{
		// timing parameters
		{"Timing (fixd)",     1}, 
			{"ITI",		0,	1.0},	// total ITI = ITI+k*errITI, k=0 if crt and k=1 if icrt, nc or bf
			{"errITI",	0,	1.0},
			{"dur",		0,	1.0},	// fixation/dots duration
			{"abortT",  0,	1.0},	// time to wait for the monkey to acquire fixation before aborting the current trial
			{NULL},
			
		// task properties
		{"Task properties (fixd)",			1},
			{ "Trial_order",	0,		1.0 },
			{ "Trial_blocks",	0,		1.0 },	// Trial_blocks: # of repetition of a full set of trials */
			{ "RepeatFlag",		-1,		1.0},
			{ "nRew",			1,		1.0},
			{ "ang_o",		    0,		1.0},
			{ "ang_step",		45,		1.0},
			{ "ang_n",			8,		1.0},
			{ "coh_lo",		    0,		0.1},
			{ "coh_hi",			999,	0.1},
			//{ "contrast_o",		1,		0.01},	// contrast multiplier to dots CLUT
			//{ "contrast_step",	20,		0.01},
			//{ "contrast_n",		4,		1},
			{NULL},
			
	    /* graphic objects (1 target and 1 dots)
		**		0 - fixation
		**		1 - dots aperture
		**		2 - dots direction
		*/
		{ "graphics",	 NUM_GR_MENUS },
			TU_XYRT_LIST,
			{ DX_DIAM,		11,		0.1 },
			{ DX_CLUT,		12,		1.0 },
			{ NULL },
	
		// dots properties
		{ "Dots properties",		 1 },
			{ DX_R,			80,		0.1},
			{ DX_T,			0,		1},
			{ DX_DIAM,		80,		0.1},
			{ DX_SPEED,		80,		0.1 },
			{ DX_SEED,		100,	1 },
			{ DX_COH,		0,		0.1 },
			{ DX_DIR,		0,		1.0 },
			{ DX_CLUT,		0,		1.0 },
			{ NULL },


	},	
	
	
	/*    Graphics objects, by name     */
	{  {DX_TARGET,	1 }, 
		{DX_DOTS,		1 }, 
		{ NULL },
	},

					
	/*     User functions     */
	{
		{NULL},
	},
	
	
	/*     Task methods     */
	&fixd_make_trials,
	&fixd_get_trial,
	&fixd_set_trial,
};
			

			
/* 
**	PUBLIC ROUTINE: fixd_make_trials
*/
void fixd_make_trials(_PRtask task)
{
  	static int coh_list[] = {0, 8, 16, 32, 64, 128, 256, 512, 999};
	int coh_n = sizeof(coh_list)/sizeof(int), 
		*cohs=NULL;
   register int i;
   int count = 0, ang_n, angs;	

			
	// determines the number and list of cohs


   int cohl = abs(TPMV(task, "coh_lo"));	// only works with +ve numbers 
   int cohh = abs(TPMV(task, "coh_hi"));

	if (cohh>cohl){ 




		// find sequence between lo and hi from coh_list as defined above
		for (i=0; i<coh_n; i++)
		{
			if (cohl>=coh_list[i] && cohh<=coh_list[i])
			{
				cohs[count] = coh_list[i];
				count++;
			}	
		}	
		coh_n = count;

	} 
	else 
	{ 


		// send just one value (abs value of coh_lo)
		coh_n   = 1;
		cohs    = SAFE_ZALLOC(long,1);
		for (i=0; i<coh_n; i++)
			if (cohl>=coh_list[i])
			{
				cohs[0] = coh_list[i];
				break;
			}		
	}

	
	// determines the number and list of directions
 
	ang_n = toy_boundi(TPMV(task, "ang_n"), 1, 1000);
	angs  = toy_seriesi(ang_n, TPMV(task, "ang_o"), TPMV(task, "ang_step"));

	
	// make 2D matrix of stimulus conditions
	tu_make_trials2D(task, "coh", coh_n, cohs, 0.1, 
						   "ang", ang_n, angs, 1.0);

	
	// free up memories
	SAFE_FREE(cohs);
	SAFE_FREE(angs);
}



/*
** PUBLIC ROUTINE: fixd_get_trial
*/
_PRtrial fixd_get_trial(_PRtask task, int reset_flag)	
{
	int trial_blocks = TPMV(task, "Trial_blocks");
	return(tu_get_random(task, trial_blocks, reset_flag));
}



/*
** PUBLIC ROUTINE: fixd_set_trial
*/
void fixd_set_trial(_PRtrial trial)
{

	// set properties for fixation point 
	_PLlist		tgm = trial->task->task_menus->lists[2];
	_PLlist		tdm = trial->task->task_menus->lists[3];

	
	




	// get dots parameters that can be overrided 
	int coh  = TDMV(trial->task, "coherence");
	int dir  = TDMV(trial->task, "direction");
	int clut = TDMV(trial->task, "color");
	int dotr = TDMV(trial->task, "r");
	int dott = TDMV(trial->task, "t");
	int dotd = TDMV(trial->task, "diameter");
	
	



	
	// decide whether to override coh and dir
	if (coh  == NULLI)			
		coh  = PL_L2PV(trial->list, 0);
	
	if (dir  == NULLI)			
		dir  = PL_L2PV(trial->list, 1);
	

	// create working copy of graphic menus
	pl_list_set_v2m(tgm)

	
	// set dots aperture r, t and d
	PL_L2PWS(tgm, 4, 1)				= dotr;
	PL_L2PWS(tgm, 5, 1)				= dott;
	PL_L2PWS(tgm, TU_XYRT_LEN, 1)	= dotd;
	
	
	// compute x, y positions of fixation point and dots
	tu_compute_xyrt(tgm);


	// Set x, y positions in actual dXtarget object
	dx_set_by_indexIV(DXF_NODRAW, 0, 1, 0, 
						1,	PL_L2PWS(tgm, 0, 0),
						2,	PL_L2PWS(tgm, 1, 0),
						3,	PL_L2PWS(tgm, TU_XYRT_LEN, 0),
						4,	PL_L2PWS(tgm, TU_XYRT_LEN+1, 0),
						ENDI);


	// Second, set properties of the dXdots object
	dx_set_by_nameIV(DXF_D1, DX_DOTS, 1, 0,
						DX_X,		PL_L2PWS(tgm, 0, 1),
						DX_Y, 		PL_L2PWS(tgm, 1, 1),
						DX_DIAM,	PL_L2PWS(tgm, TU_XYRT_LEN, 1),
						DX_CLUT,	clut,
						DX_COH,		coh,
						DX_DIR,		dir,
						DX_SPEED,  	PL_L2PVS(tdm, 3 ,0),
						NULL);

	
	// drop codes
	pl_ecodes_by_nameV(dx_get_object(DX_TARGET), 7000,
					   DX_X,		0, 	I_FIXXCD,
					   DX_Y,		0, 	I_FIXYCD,
					   DX_CLUT,		0, 	I_FIXLCD,
					   NULL);
	
	pl_ecodes_by_nameV(dx_get_object(DX_DOTS), 7000,
					   DX_COH,		0, 	I_COHCD,
					   DX_DIR,		0, 	I_DOTDIRCD,
					   DX_SEED,		0, 	I_DTVARCD,
					   NULL);
	
	
}







